home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Frameworks / Hsoi's App Shell 1.0a4 / HAS Other Source / WASTE 1.3a4 Distribution / WASTE 1.3a4 / Source / WEScraps.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-04-04  |  11.2 KB  |  479 lines  |  [TEXT/CWIE]

  1. /*
  2.  *    WEScraps.c
  3.  *
  4.  *    WASTE PROJECT
  5.  *  Routines for Manipulating Style Scraps and Object Soups
  6.  *
  7.  *  Copyright (c) 1993-1997 Marco Piovanelli
  8.  *    All Rights Reserved
  9.  *
  10.  *  C port by Dan Crevier
  11.  *
  12.  */
  13.  
  14.  
  15. #include "WASTEIntf.h"
  16.  
  17. pascal OSErr _WEPrependStyle(Handle hStyleScrap, const WERunInfo *info, SInt32 offsetDelta)
  18. {
  19.     // compare the stylistic attributes in info with the first element of the specified
  20.     // style scrap: if they differ, prepend a new element to the style scrap.
  21.     // in any case, advance all character offsets in the style scrap by offsetDelta
  22.  
  23.     TEStyleScrap *pScrap;
  24.     TEStyleScrapElement entry;
  25.     SInt16 i;
  26.     OSErr err;
  27.  
  28.     pScrap = * (TEStyleScrapHandle) hStyleScrap;
  29.  
  30.     // compare this style info with that stored in the first entry of our private style scrap
  31.     if (!_WEBlockCmp(&pScrap->scrpStyleTab[0].scrpTEAttrs, &info->runAttrs, sizeof(TERunAttributes)))
  32.     {
  33.         // insert a new style scrap entry at the beginning of the style scrap
  34.         entry.scrpStartChar = 0;
  35.         entry.scrpTEAttrs = * (TERunAttributes *) &info->runAttrs;
  36.  
  37.         if ((err = _WESplice(hStyleScrap, &entry, sizeof(entry), sizeof(SInt16))) != noErr)
  38.         {
  39.             return err;
  40.         }
  41.  
  42.         pScrap = * (TEStyleScrapHandle) hStyleScrap;
  43.  
  44.         // increment entry count
  45.         pScrap->scrpNStyles++;
  46.  
  47.     } // if not _WEBlockCmp
  48.  
  49.     // update char offsets within the style scrap
  50.     for ( i = pScrap->scrpNStyles - 1; i > 0; i-- )
  51.     {
  52.         pScrap->scrpStyleTab[i].scrpStartChar += offsetDelta;
  53.     }
  54.  
  55.     return noErr;
  56. }
  57.  
  58. pascal OSErr _WEAppendStyle(Handle hStyleScrap, const WERunInfo *info, SInt32 offset)
  59. {
  60.  
  61.     // compare the stylistic attributes in info with the last entry of the specified
  62.     // style scrap: if they differ, append a new entry to the style scrap.
  63.  
  64.     TEStyleScrap *pScrap;
  65.     TEStyleScrapElement entry;
  66.     OSErr err;
  67.  
  68.     pScrap = * (TEStyleScrapHandle) hStyleScrap;
  69.     // compare this style info with that stored in the first entry of our private style scrap
  70.     if (!_WEBlockCmp(&pScrap->scrpStyleTab[pScrap->scrpNStyles - 1].scrpTEAttrs,
  71.         &info->runAttrs, sizeof(TERunAttributes)))
  72.     {
  73.  
  74.         // create a new style scrap entry
  75.         entry.scrpStartChar = offset;
  76.         entry.scrpTEAttrs = * (TERunAttributes *) &info->runAttrs;
  77.  
  78.         // append it at the end of the style scrap
  79.         if ((err = _WESplice(hStyleScrap, &entry, sizeof(entry), -1)) != noErr)
  80.         {
  81.             return err;
  82.         }
  83.  
  84.         // increment scrap counter
  85.         pScrap = * (TEStyleScrapHandle) hStyleScrap;
  86.         pScrap->scrpNStyles++;
  87.  
  88.     } // if not _WEBlockCmp
  89.  
  90.     // return result code
  91.     return noErr;
  92. }
  93.  
  94. #if WASTE_OBJECTS
  95.  
  96. pascal OSErr _WEPrependObject(Handle hSoup, const WERunInfo *info, SInt32 offsetDelta)
  97. {
  98.     // if info describes an embedded object, prepend a new object descriptor,
  99.     // complete with the associated object data, to the specified soup.
  100.     // in any case, advance all character offsets in the soup by offsetDelta
  101.  
  102.     WEObjectDescHandle hObjectDesc = info->runAttrs.runStyle.tsObject;
  103.     Handle hObjectData = nil;
  104.     FlavorType objectType;
  105.     Boolean disposeData;
  106.     Ptr pSoup;
  107.     WESoup soup;
  108.     Size soupSize, objectDataSize, extraSize;
  109.     OSErr err;
  110.  
  111.     // get size of existing soup
  112.     soupSize = GetHandleSize(hSoup);
  113.  
  114.     if (hObjectDesc != nil)
  115.     {
  116.         // create a temporary handle for the streaming callback
  117.         if ((err = _WEAllocate(0, kAllocTemp, &hObjectData)) != noErr)
  118.         {
  119.             goto cleanup;
  120.         }
  121.  
  122.         // get the object type/data
  123.         if ((err = _WEStreamObject(weToSoup, &objectType, &hObjectData, &disposeData, hObjectDesc)) != noErr)
  124.         {
  125.             goto cleanup;
  126.         }
  127.  
  128.         // get size of object data
  129.         objectDataSize = GetHandleSize(hObjectData);
  130.  
  131.         // extraSize is size of descriptor + size of object data
  132.         extraSize = sizeof(soup) + objectDataSize;
  133.  
  134.         // fill in a soup item
  135.         BLOCK_CLR(soup);
  136.         soup.soupType = objectType;
  137.         soup.soupSize = (*hObjectDesc)->objectSize;
  138.         soup.soupDataSize = objectDataSize;
  139.  
  140.         // make room for the descriptor and the object data
  141.         if ((err = _WESplice(hSoup, nil, extraSize, 0)) != noErr)
  142.         {
  143.             goto cleanup;
  144.         }
  145.  
  146.         // insert the new object descriptor at the beginning
  147.         pSoup = *hSoup;
  148.         BlockMoveData(&soup, pSoup, sizeof(soup));
  149.  
  150.         // copy the object data
  151.         BlockMoveData(*hObjectData, pSoup + sizeof(soup), objectDataSize);
  152.     }
  153.     else
  154.     {
  155.         pSoup = *hSoup;
  156.         extraSize = 0;
  157.     }
  158.  
  159.     // update char offsets within the soup
  160.     while (soupSize > 0)
  161.     {
  162.         pSoup += extraSize;
  163.  
  164.         //    we have to use BlockMoveData to access descriptors within
  165.         //    the soup, as they might be odd-aligned (duh!) and that would
  166.         //    cause fatal address errors on 68000 CPUs
  167.  
  168.         BlockMoveData(pSoup, &soup, sizeof(soup));
  169.         soup.soupOffset += offsetDelta;
  170.         BlockMoveData(&soup, pSoup, sizeof(soup));
  171.         extraSize = sizeof(soup) + soup.soupDataSize;
  172.         soupSize -= extraSize;
  173.     }
  174.  
  175.     err = noErr;
  176.  
  177. cleanup:
  178.     if (disposeData)
  179.     {
  180.         _WEForgetHandle(&hObjectData);
  181.     }
  182.  
  183.     return err;
  184.  
  185. }
  186.  
  187. pascal OSErr _WEAppendObject(Handle hSoup, const WERunInfo *info, SInt32 offset)
  188. {
  189.  
  190.     // if info describes an embedded object, append a new object descriptor,
  191.     // complete with the associated object data, to the specified soup.
  192.  
  193.     WEObjectDescHandle hObjectDesc = info->runAttrs.runStyle.tsObject;
  194.     Handle hObjectData = nil;
  195.     FlavorType objectType;
  196.     WESoup soup;
  197.     Boolean saveDataLock;
  198.     Boolean disposeData;
  199.     OSErr err;
  200.  
  201.     if (hObjectDesc != nil)
  202.     {
  203.         // create a temporary handle for the streaming callback
  204.         if ((err = _WEAllocate(0, kAllocTemp, &hObjectData)) != noErr)
  205.         {
  206.             goto cleanup;
  207.         }
  208.  
  209.         // get the object type/data
  210.         if ((err = _WEStreamObject(weToSoup, &objectType, &hObjectData, &disposeData, hObjectDesc)) != noErr)
  211.         {
  212.             goto cleanup;
  213.         }
  214.  
  215.         // fill in a soup item
  216.         BLOCK_CLR(soup);
  217.         soup.soupOffset = offset;
  218.         soup.soupType = objectType;
  219.         soup.soupSize = (*hObjectDesc)->objectSize;
  220.         soup.soupDataSize = GetHandleSize(hObjectData);
  221.  
  222.         // append it to the soup handle
  223.         if ((err = _WESplice(hSoup, &soup, sizeof(soup), -1)) != noErr)
  224.         {
  225.             goto cleanup;
  226.         }
  227.  
  228.         // append the actual object data to the soup handle
  229.         saveDataLock = _WESetHandleLock(hObjectData, true);
  230.         err = _WESplice(hSoup, *hObjectData, soup.soupDataSize, -1);
  231.         _WESetHandleLock(hObjectData, saveDataLock);
  232.         if (err != noErr)
  233.         {
  234.             goto cleanup;
  235.         }
  236.     } // if object reference is not nil
  237.  
  238.     err = noErr;
  239.  
  240. cleanup:
  241.     if (disposeData)
  242.     {
  243.         _WEForgetHandle(&hObjectData);
  244.     }
  245.  
  246.     return err;
  247.  
  248. }
  249.  
  250. #endif
  251.  
  252. pascal OSErr WECopyRange(SInt32 rangeStart, SInt32 rangeEnd, Handle hText,
  253.                     Handle hStyles, Handle hSoup, WEHandle hWE)
  254. {
  255.  
  256.     // Make a copy of the specified range of text: store the characters in hText
  257.     // and the associated style scrap in hStyles.  The handles are resized as necessary.
  258.     // Specify nil in hText or hStyles if you don't want the corresponding info returned.
  259.  
  260.     WEPtr pWE;
  261.     TEStyleScrapElement *pEntry;
  262.     SInt32 rangeLength;
  263.     SInt32 firstRun, nRuns, i;
  264.     SInt32 startChar;
  265.     WERunInfo info;
  266.     Boolean saveWELock;
  267.     OSErr err;
  268.  
  269.     // lock the WE record
  270.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  271.     pWE = *hWE;
  272.  
  273.     // range-check parameters and reorder them if necessary
  274.     rangeStart = _WEPinInRange(rangeStart, 0, pWE->textLength);
  275.     rangeEnd = _WEPinInRange(rangeEnd, 0, pWE->textLength);
  276.     _WEReorder(&rangeStart, &rangeEnd);
  277.     rangeLength = rangeEnd - rangeStart;
  278.  
  279.     if (hText != nil)
  280.     {
  281.         // resize the given handle
  282.         SetHandleSize(hText, rangeLength);
  283.         if ((err = MemError()) != noErr)
  284.         {
  285.             goto cleanup;
  286.         }
  287.  
  288.         // copy the text range
  289.         BlockMoveData(*pWE->hText + rangeStart, *hText, rangeLength);
  290.     }
  291.  
  292.     // make the soup handle zero-length
  293.     if (hSoup != nil)
  294.     {
  295.         SetHandleSize(hSoup, 0);
  296.         if ((err = MemError()) != noErr)
  297.         {
  298.             goto cleanup;
  299.         }
  300.     }
  301.  
  302.     if ((hStyles != nil) || (hSoup != nil))
  303.     {
  304.         // count how many style runs there are in the selection range
  305.         firstRun = WEOffsetToRun(rangeStart, hWE);
  306.         nRuns = WEOffsetToRun(rangeEnd - 1, hWE) - firstRun + 1;
  307.  
  308.         if (hStyles != nil)
  309.         {
  310.             // resize the given style scrap handle and lock it in high heap
  311.             SetHandleSize(hStyles, (nRuns * sizeof(ScrpSTElement)) + sizeof(SInt16));
  312.             if ((err = MemError()) != noErr)
  313.             {
  314.                 goto cleanup;
  315.             }
  316.             HLockHi(hStyles);
  317.  
  318.             // fill in the entry count in the style scrap
  319.             // pin the entry count at 32,767
  320.             (* (TEStyleScrapHandle) hStyles)->scrpNStyles = (nRuns < SHRT_MAX) ? nRuns : SHRT_MAX;
  321.         }
  322.  
  323.         pEntry = & ((* (TEStyleScrapHandle) hStyles)->scrpStyleTab[0]);
  324.         // loop through every style run in the selection range
  325.         for ( i = 0; i < nRuns; i++ )
  326.         {
  327.             _WEGetIndStyle(firstRun + i, &info, hWE);
  328.  
  329.             // calculate the start character for this style run, relative to the beginning of the range
  330.             startChar = info.runStart - rangeStart;
  331.             if (startChar < 0)
  332.             {
  333.                 startChar = 0;
  334. #if WASTE_OBJECTS
  335.                 info.runAttrs.runStyle.tsObject = nil;
  336. #endif
  337.             }
  338.             if (hStyles != nil)
  339.             {
  340.                 info.runAttrs.runStyle.tsFlags = 0; // don't export internal flags
  341.                 pEntry->scrpStartChar = startChar;
  342.                 pEntry->scrpTEAttrs = * (TERunAttributes *) &info.runAttrs;
  343.                 pEntry++;
  344.             }
  345.  
  346. #if WASTE_OBJECTS
  347.             if (hSoup != nil)
  348.             {
  349.                 // if this style run references an embedded object, append it to the "soup"
  350.                 if (info.runAttrs.runStyle.tsObject != nil)
  351.                 {
  352.                     if ((err = _WEAppendObject(hSoup, &info, startChar)) != noErr)
  353.                     {
  354.                         goto cleanup;
  355.                     }
  356.                 }
  357.             }
  358. #endif
  359.  
  360.         }
  361.     }
  362.     // clear result code
  363.     err = noErr;
  364.  
  365. cleanup:
  366.  
  367.     // unlock the style scrap handle
  368.     if (hStyles != nil)
  369.     {
  370.         HUnlock(hStyles);
  371.     }
  372.  
  373.     // unlock the WE record
  374.     _WESetHandleLock((Handle) hWE, saveWELock);
  375.     // return result code
  376.     return err;
  377. }
  378.  
  379. pascal OSErr WECopy(WEHandle hWE)
  380. {
  381.     // Copy the selection range to the desk scrap
  382.  
  383.     WEPtr pWE;
  384.     AEDesc d[3] = { { kTypeText, nil }, { kTypeStyles, nil }, { kTypeSoup, nil } };
  385.     Handle hItem;
  386.     Size itemSize;
  387.     SInt16 i, numTypes;
  388.     Boolean saveWELock;
  389.     Boolean saveDataLock;
  390.     Boolean disposeData = true;
  391.     OSErr err;
  392. #if WASTE_OBJECTS
  393.     WEObjectDescHandle hObjectDesc = nil;
  394. #endif
  395.  
  396.     // lock the WE record
  397.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  398.     pWE = *hWE;
  399.  
  400.     // return weEmptySelectionErr if the selection range is empty
  401.     if (pWE->selStart == pWE->selEnd)
  402.     {
  403.         err = weEmptySelectionErr;
  404.         goto cleanup;
  405.     }
  406.  
  407.     // clear the desk scrap
  408.     if ((err = ZeroScrap()) != noErr)
  409.     {
  410.         goto cleanup;
  411.     }
  412.  
  413. #if WASTE_OBJECTS
  414.     numTypes = (BTST(pWE->features, weFMonoStyled) || (WEGetSelectedObject(&hObjectDesc, hWE) == noErr)) ? 1 : 3;
  415. #else
  416.     numTypes = BTST(pWE->features, weFMonoStyled) ? 1 : 2;
  417. #endif
  418.  
  419.     // allocate some temporary handles
  420.     for ( i = 0; i < numTypes; i++ )
  421.     {
  422.         if ((err = _WEAllocate(0, kAllocTemp, &d[i].dataHandle)) != noErr)
  423.         {
  424.             goto cleanup;
  425.         }
  426.     }
  427.  
  428. #if WASTE_OBJECTS
  429.     if (hObjectDesc != nil)
  430.     {
  431.         if ((err = _WEStreamObject(weToScrap, &d[0].descriptorType, &d[0].dataHandle,
  432.                     &disposeData, hObjectDesc)) != noErr)
  433.         {
  434.             goto cleanup;
  435.         }
  436.     }
  437.     else
  438. #endif
  439.     {
  440.         // make a copy of the selection text and styles and create an object "soup"
  441.         if ((err = WECopyRange(pWE->selStart, pWE->selEnd,
  442.             d[0].dataHandle, d[1].dataHandle, d[2].dataHandle, hWE)) != noErr)
  443.         {
  444.             goto cleanup;
  445.         }
  446.     }
  447.  
  448.     // copy the items to the desk scrap
  449.     for ( i = 0; i < numTypes; i++ )
  450.     {
  451.         hItem = d[i].dataHandle;
  452.         itemSize = GetHandleSize(hItem);
  453.         if (itemSize > 0)
  454.         {
  455.             saveDataLock = _WESetHandleLock(hItem, true);
  456.             err = PutScrap(itemSize, d[i].descriptorType, *hItem);
  457.             _WESetHandleLock(hItem, saveDataLock);
  458.             if (err != noErr)
  459.             {
  460.                 goto cleanup;
  461.             }
  462.         }
  463.     }
  464.  
  465.     // clear result code
  466.     err = noErr;
  467.  
  468. cleanup:
  469.     // clean up
  470.     if (disposeData)
  471.     {
  472.         _WEForgetHandle(&d[0].dataHandle);
  473.         _WEForgetHandle(&d[1].dataHandle);
  474.         _WEForgetHandle(&d[2].dataHandle);
  475.     }
  476.     _WESetHandleLock((Handle) hWE, saveWELock);
  477.     return err;
  478. }
  479.